
// import haxe.ds.Array;
// import oimo.m.Vec3;
// import oimo.m.M;

import { Vec3 } from "../../../common/Vec3";
import { M } from "../../../common/M";
import { BvhProxy } from "./BvhProxy";

/**
 * numberernal class.
 *
 * BVH Node
 */


export class BvhNode {
	// for object pool
	_next: BvhNode;

	// for BvhTree.leafList
	_prevLeaf: BvhNode;
	_nextLeaf: BvhNode;

	_children: Array<BvhNode>;
	_childIndex: number; // must be 0 or 1 regardless of having parent
	_parent: BvhNode;
	_height: number;
	_proxy: BvhProxy;

	// node's aabb. if the node is a leaf, the aabb is equal to the proxy's one.
	_aabbMin: Vec3;
	_aabbMax: Vec3;

	// used by other classes
	_tmp: Vec3;

	constructor() {
		this._next = null;
		this._prevLeaf = null;
		this._nextLeaf = null;
		this._children = new Array<BvhNode>(2);
		this._childIndex = 0;
		this._parent = null;
		this._height = 0;
		this._proxy = null;
		this._aabbMin = new Vec3();
		this._aabbMax = new Vec3();
	}

	// --- internal ---


	public _setChild(index: number, child: BvhNode): void {
		this._children[index] = child;
		child._parent = this;
		child._childIndex = index;
	}


	public _removeReferences(): void {
		this._next = null;
		this._childIndex = 0;
		this._children[0] = null;
		this._children[1] = null;
		this._childIndex = 0;
		this._parent = null;
		this._height = 0;
		this._proxy = null;
	}


	public _computeAabb(): void {
		var c1: BvhNode = this._children[0];
		var c2: BvhNode = this._children[1];
		M.vec3_min(this._aabbMin, c1._aabbMin, c2._aabbMin);
		M.vec3_max(this._aabbMax, c1._aabbMax, c2._aabbMax);
	}


	public _computeHeight(): void {
		var h1: number = this._children[0]._height;
		var h2: number = this._children[1]._height;
		this._height = (h1 > h2 ? h1 : h2) + 1;
	}


	public _perimeter(): number {
		var size: Vec3 = new Vec3();
		M.vec3_sub(size, this._aabbMax, this._aabbMin);
		var x: number = M.vec3_get(size, 0);
		var y: number = M.vec3_get(size, 1);
		var z: number = M.vec3_get(size, 2);
		return x * (y + z) + y * z;
	}

}
